﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

namespace ShareHelper
{
    internal class Info
    {
        /// <summary>
        /// 账号Id 位置序号
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 完成状态  默认false 未完成
        /// </summary>
        public bool State { get; set; }

        /// <summary>
        /// 账号文本
        /// </summary>
        public string Accout { get; set; }

        /// <summary>
        /// 账号调用次数
        /// </summary>
        public int Count { get; set; }

        /// <summary>
        /// 账号是否取出
        /// </summary>
        public bool GetOut { get; set; }
    }

    /// <summary>
    /// 账号集合帮助类
    /// </summary>
    public class Account
    {
        private static Regex Regex { get; }

        static Account()
        {
            Regex = new Regex(@"\s*", RegexOptions.Compiled);
        }

        /// <summary>
        /// 账号 集合 线程安全的无序集合
        /// </summary>
        private ConcurrentBag<Info> AccountList { get; set; }

        /// <summary>
        /// 当前使用账号
        /// </summary>
        private string UserAccount { get; set; }

        /// <summary>
        /// 是否循环使用默认为假
        /// </summary>
        private bool AutoReset { get; }

        /// <summary>
        /// 导入账号数量
        /// </summary>
        public int Count
        {
            get
            {
                if (AccountList.IsEmpty) return 0;
                return AccountList.Count;
            }
        }

        /// <summary>
        /// 已完成 结束 账号数量
        /// </summary>
        public int Finish
        {
            get
            {
                if (Count > 0) return AccountList.Count(a => a.State);
                return 0;
            }
        }

        /// <summary>
        /// 最大调用次数
        /// </summary>
        public int MaxCount
        {
            get
            {
                if (Count > 0) return AccountList.Max(a => a.Count);
                return 0;
            }
        }

        /// <summary>
        /// 导入账号的路径
        /// </summary>
        public string UserPath { get; private set; }

        /// <summary>
        /// 日志路径
        /// </summary>
        private string LogPath;

        /// <summary>
        /// 错误上线
        /// </summary>
        public int ErrNum { get; }

        /// <summary>
        /// 账号集合帮助类
        /// </summary>
        /// <param name="num">错误上线</param>
        /// <param name="reset">是否循环使用默认为假</param>
        public Account(int num = 3, bool reset = false)
        {
            ErrNum = num;
            UserAccount = string.Empty;
            AutoReset = reset;
            AccountList = new ConcurrentBag<Info>();
        }

        private object ObLocl { get; } = new object();

        /// <summary>
        /// 已加锁 线程安全
        /// 获取 未完成 且 计数次数最小次数的账号
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public bool NextUser(out string[] account)
        {
            account = null;
            if (AccountList.IsEmpty) return false;
            lock (ObLocl)
            {
                //-------------------获取没有完成 且 没有 取出 取出次数小于十的账号 -------
                var data = AccountList.Where(a => !a.State && !a.GetOut && a.Count < ErrNum);
                if (data.Count() > 0)
                {
                    //获取次数最小 且 Id考前的第一个
                    var info = data.OrderBy(b => b.Count).ThenBy(a => a.Id).First();
                    UserAccount = info.Accout;
                    info.GetOut = true;//账号已获取
                    info.Count++;//账号已获取
                    account = UserAccount.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
                    return true;
                }// 账号数量 大于0   且 循环使用
                else if (AutoReset)
                {
                    var accountList = AccountList.Select(a => new Info { Accout = a.Accout, Id = a.Id });
                    AccountList = new ConcurrentBag<Info>(accountList);
                    return NextUser(out account);
                }
                return false;
            }
        }

        /// <summary>
        /// 写出文档  线程安全
        /// </summary>
        /// <param name="Account">写出账号 账号为空 默认使用 内部 记录账号 多线程会错乱</param>
        /// <param name="Msg">写出内容</param>
        /// <param name="State">是否执行成功 默认True(成功不会再使用本账号)</param>
        public void Write(string Account = null, string Msg = null, bool State = true)
        {
            var account = AccountList;
            if (account.IsEmpty) return;
            if (string.IsNullOrEmpty(Account)) Account = UserAccount;//账号为空 默认使用 记录账号
            if (string.IsNullOrEmpty(Account)) return; //输入账号 和 记录账号为空  需要修改账号为空 直接返回
            var Info = account.FirstOrDefault(a => a.Accout.StartsWith(Account));//寻找账号所对应的对象
            if (Info == null) return;//没有找到账号对应的对象
            //归还账号
            Info.GetOut = false;
            //执行 完毕  或 调用次数大于十  都算执行完毕
            State = State ? State : Info.Count >= ErrNum;
            //账号执行状态
            Info.State = State;
            //执行完毕 且 写出消息不为空  日志路径不为空 才有写出日志
            if (State && !string.IsNullOrEmpty(Msg) && !string.IsNullOrEmpty(LogPath))
            {
                var str = $"{Info.Accout}--{DateTime.Now:yyyy-MM-dd HH:mm:ss}--{Msg}\r\n";
                File.AppendAllText(LogPath, str);
            }
        }

        /// <summary>
        /// 导入账号路径 分割符为 -
        /// </summary>
        /// <param name="path">账号路径</param>
        /// <param name="length">账号长度</param>
        /// <returns>账号为空 返回 false</returns>
        public bool AddAccount(string path, int length = 2)
        {
            string Msg;
            var account = new ConcurrentBag<Info>();
            path = path.Replace(((char)0x202a).ToString(), null);
            if (string.IsNullOrEmpty(path)) Msg = "账号路径,不能为空";
            else
            {
                //忽略字符串大小写
                var IsTxt = path.EndsWith(".txt", StringComparison.CurrentCultureIgnoreCase);
                if (IsTxt && File.Exists(path))
                {
                    UserPath = path;
                    LogPath = Path.ChangeExtension(UserPath, "log");
                    var encoding = EncodingType.GetType(path);
                    string[] allAcc = File.ReadAllLines(path, encoding);
                    foreach (var item in allAcc)
                    {
                        string[] user = item.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
                        if (user.Length >= length)
                            account.Add(new Info { Accout = item, Id = account.Count });
                    }
                    if (account.Count > 0)
                        Msg = "账号导入成功";
                    else
                        Msg = "导入账号文本,格式不符或为空";
                }
                else
                    Msg = "账号路径错误,请检查路径文本";
            }
            if (!string.IsNullOrEmpty(Msg)) Log.Info(Msg);
            AccountList = account;
            return Count > 0;
        }

        /// <summary>
        /// 导入账号
        /// </summary>
        /// <param name="length">账号长度</param>
        /// <param name="user"></param>
        /// <returns></returns>
        public bool AddAccount(int length = 2, params string[] user)
        {
            var data = new List<string>();
            foreach (var item in user)
            {
                var text = Regex.Replace(item, string.Empty);
                if (!string.IsNullOrEmpty(text)) data.Add(text);
            }
            if (data.Count >= length) AccountList.Add(new Info { Accout = string.Join("-", data), Id = AccountList.Count });
            else Log.Info($"导入账号{string.Join("-", user)},长度不足:{length}");
            return AccountList.Count > 0;
        }
    }
}